package devTest.Game 
{
	import flash.display.Shape;
	import flash.display.Stage;
	import flash.display.Sprite;
	import devTest.Ball.CBall;
	import devTest.Paddle.CPaddle;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.events.KeyboardEvent;
	import flash.events.TimerEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.text.Font;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.utils.Timer;

	
	/**
	 * ...
	 * @author miquel
	 */
	
	public class CGame extends Sprite 
	{
		//source code from 'http://divillysausages.com/node/142' to export fonts
		[Embed(source = "../../../lib/fonts/OCRAExt.ttf",
		    fontName = "OCR", 
			mimeType = "application/x-font-truetype", 
			fontWeight="normal", 
			fontStyle="normal", 
//			unicodeRange="englishRange", 
			advancedAntiAliasing="true", 
			embedAsCFF = "false")]
		private var myEmbeddedFont:	Class;

		//textfields
		private var m_pGoalsA:		TextField 	= null;
		private var m_pGoalsB:		TextField 	= null;

		//xml values
		private var m_sDataXML:		String 		= "./XML/initXML.xml"
		private var m_pExternXML:	XML 		= null;
		
		//timers
		private var timerBeginMatch:Timer 		= null;

		//stage
		private var myStage:		Stage 		= null;
		
		//game variables
		private var m_iGoalsA:		int 		= 0;
		private var m_iGoalsB:		int 		= 0;
		private var m_iMaxGoals:	int 		= 0;
		private var m_iStateGame:	int 		= 0;	//0-start game, 1-goal P1, 2-goal P2, 3-end game
		
		//game objects
		private var m_pPaddle1:		CPaddle 	= null;
		private var m_pPaddle2:		CPaddle 	= null;
		private var m_pBall:		CBall 		= null;
		private var m_pLine:		Shape 		= null;	

		//screens
		private var m_iActScreen:	int 		= 0;
		
		//gets
		public function GetStateGame():int 	{  return m_iStateGame; }
		public function GetGoalsA	():int	{  return m_iGoalsA;	}
		public function GetGoalsB	():int	{  return m_iGoalsB;	}

		
		/**
		 * constructor
		 */
		public function CGame(s:Stage) 
		{
			super();			
			myStage = s;
		}
		

		/**
		 * Init: Prepare listeners, read XML file to give properties to objects
		 * 			Start some timers, to begin the game
		 * 			@return if init is ok
		 */
		public function Init():Boolean
		{					
			myStage.focus = this;
			
			//updating game status
			myStage.addEventListener(Event.ENTER_FRAME, Update);

			//listen keys
			myStage.addEventListener(KeyboardEvent.KEY_DOWN, PressKey);
			myStage.addEventListener(KeyboardEvent.KEY_UP, ReleaseKey);
			
			//reading xml
			if ( LoadXML(m_sDataXML) )
			{
				trace("CGame: Init-> Ok reading xml: " + m_sDataXML);
			}
			else
			{
				trace("2:CGame: Init-> Problems reading xml: " + m_sDataXML);
				return false;
			}

			//timer to start de match
			timerBeginMatch = new Timer(1500, 1);
			if (timerBeginMatch != null)
			{
				timerBeginMatch.addEventListener(TimerEvent.TIMER, StartGame);
			}
			else
			{
				trace("2:CGame: Init-> the start match timer was not created ");
				return false;
			}
												
			return true;
		}
				
		
		/**
		 * PressKey: detects if a key was pressed
		 * @eventType : KeyboardEvent (press key)
		 */
		private function PressKey(e:KeyboardEvent):void
		{
			switch (e.keyCode) 
			{
				//key control
				case m_pPaddle1.GetKeyUp() 	 :m_pPaddle1.SetPressedKeyUp(true);		break;
				case m_pPaddle2.GetKeyUp() 	 :m_pPaddle2.SetPressedKeyUp(true);		break;
				case m_pPaddle1.GetKeyDown() :m_pPaddle1.SetPressedKeyDown(true);	break;
				case m_pPaddle2.GetKeyDown() :m_pPaddle2.SetPressedKeyDown(true);	break;
			}
		}
		

		/**
		 * PressKey: detects if a key was released
		 * @eventType : KeyboardEvent (release key)
		 */
		private	function ReleaseKey(e:KeyboardEvent):void
		{
			switch (e.keyCode) 
			{
				//key control
				case m_pPaddle1.GetKeyUp() 	 :m_pPaddle1.SetPressedKeyUp(false);	break;
				case m_pPaddle2.GetKeyUp() 	 :m_pPaddle2.SetPressedKeyUp(false);	break;
				case m_pPaddle1.GetKeyDown() :m_pPaddle1.SetPressedKeyDown(false);	break;
				case m_pPaddle2.GetKeyDown() :m_pPaddle2.SetPressedKeyDown(false);	break;
				
				//reload xml info
 				case 120:ReloadXML		  () ;										break;		//KEY_F9
			}
		}

		
		/**
		 * Update: function for each frame
		 * @eventType : Event EnterFrame
		 */
		//public function Update(e:TimerEvent):void
		public function Update(e:Event):void
		{
			//players control
			if (m_pPaddle1 != null)
				m_pPaddle1.Update();
				
			if (m_pPaddle2 != null)	
				m_pPaddle2.Update();
			
			//anybody got the max score and wins
			if ( (m_iGoalsA > m_iMaxGoals) || (m_iGoalsB > m_iMaxGoals) )
			{
				m_iStateGame = 3;	//end of game
			}
			else // in video, the eleven goal doesn't appear
			{
				//update scores
				if(m_pGoalsA != null)
					m_pGoalsA.text = m_iGoalsA.toString();
				
				if (m_pGoalsB != null)
					m_pGoalsB.text = m_iGoalsB.toString();

			}

			//ball movement. 
			if ( m_pBall != null)
			{
				m_pBall.GetPaddlesPosition(m_pPaddle1.y, m_pPaddle2.y);
				var result: int = m_pBall.Move();

				//goal at right of the screen (to player 1)
				if (result > 0)
				{
					m_iStateGame = 1;
					m_iGoalsA++;
					m_pBall.BallToMidfield()
					if (timerBeginMatch != null)
					{
						timerBeginMatch.start();
					}

					trace("goal of P1: " + m_iGoalsA + ":" + m_iGoalsB );
				}
				
				//goal at left of the screen (to player 2)
				else if (result < 0)
				{
					m_iStateGame = 2;
					m_iGoalsB++;
					m_pBall.BallToMidfield()
					if (timerBeginMatch != null)
					{
						timerBeginMatch.start();
					}
					trace("goal of P2: " + m_iGoalsA + ":" + m_iGoalsB );
				}			
			}
		}
		

		/**
		 * Done: Not useful. Release Garbage Collector
		 */
		public function Done():void
		{
			trace("exit game screen");
		}
		

		/**
		 * ReloadXML: Reloads the XML file in run-time
		 */
		public function ReloadXML():void
		{
				//stops timers to avoid problems
				timerBeginMatch.stop();
				
				//recreate objects of game
				RemoveObjectsOfGame();
				LoadXML(m_sDataXML);
		}
		

		/**
		 * LoadXML: Loads a XML file with useful data to init objects
		 */
		public function LoadXML(_fileXML:String):Boolean
		{
			//create a url loader
			var l_pLoader:URLLoader = null;
			l_pLoader = new URLLoader();
			if (l_pLoader != null)
			{
				trace("CGame: LoadXML -> URLLoader created successful");
				
				//add listeners
				SetListeners(l_pLoader);

				//create the request object
				var l_pRequest:URLRequest = null;
				l_pRequest = new URLRequest(_fileXML);
				
				if (l_pRequest != null)
				{
					trace("CGame: LoadXML -> URLRequest created successful");
					//load it
					l_pLoader.load(l_pRequest);
				}
				else
				{
					trace("2:CGame: LoadXML -> URLRequest not created");
					return false;
				}
			}
			else
			{
				trace("2:CGame: LoadXML -> URLLoader not created");
				return false;
			}

			return true;
		}
		

		/**
		 * SetListeners: detects load file complete
		 * @eventType: IEventDispatcher
		 */
		private function SetListeners(dispatcher:IEventDispatcher):void 
		{
			dispatcher.addEventListener(Event.COMPLETE, CompleteHandler);
		}
	 

		/**
		 * CompleteHandler: is executed when the load is completed
		 * @eventType: Event 
		 */
		private function CompleteHandler(event:Event):Boolean 
		{
			//load the xml file information using a urlloader
			var loader:URLLoader = null;
			loader = event.target as URLLoader;
			if (loader != null)
			{
				trace("CGame: completeHandler -> URLLoader created successful");
				//object with information about xml file
				m_pExternXML = null;
				m_pExternXML = new XML(loader.data);
				if (m_pExternXML != null)
				{
					trace("CGame: completeHandler -> XML created successful");
					//create objects of game
					if ( CreateObjectsOfGame(m_pExternXML) )
					{
						trace("CGame: completeHandler -> game's objects created successful");

						//ball must to know dimensions of paddles. (We supose the paddles are equals)
						SetPaddleValuesToBall();

						//restart timers
						timerBeginMatch.start();
						
						return true;
					}
					else
					{
						trace("2:CGame: completeHandler -> Problems creating game's objects");
						return false;
					}
				}
				else
				{
					trace("2:CGame: completeHandler -> XML was not created");
					return false;
				}
			}
			else
			{
				trace("2:CGame: completeHandler -> URLLoader was not created");				
				return false;
			}
		}
		

		/**
		 * SetPaddleValuesToBall: ball must to know dimensions of paddles. (We supose the paddles are equals)
		 */
		public function SetPaddleValuesToBall():void 
		{
			m_pBall.GetPaddlesDimensionals(m_pPaddle1.height, m_pPaddle1.width, m_pPaddle1.GetDividers());
			m_pBall.GetPaddlesPositionInit(m_pPaddle1.x, m_pPaddle1.y, m_pPaddle2.x, m_pPaddle2.y);
		}
		
		
		/**
		 * CreateObjectsOfGame: create objects of game
		 * @param : the node with xml info tree
		 * @return : if objects were created right
		 */
		public function CreateObjectsOfGame(m_pExternXML:XML):Boolean 
		{
			for each(var l_pNode:XML in m_pExternXML.elements())
			{
				//creates paddle1
				if ((l_pNode.@objclass == "paddle") && (l_pNode.@name == "pad1"))
				{
					m_pPaddle1 = new CPaddle(myStage);
					if (m_pPaddle1 != null)
					{	
						trace("CGame: CreateObjectsOfGame -> paddle1 created successful");
						if (  m_pPaddle1.Init(l_pNode) )
							addChild (m_pPaddle1);
						else
							return false;
					}
					else
					{
						trace("2:CGame: CreateObjectsOfGame -> paddle1 was not created ");
						return false;
					}
				}
				
				//creates paddle2
				if ((l_pNode.@objclass == "paddle") && (l_pNode.@name == "pad2"))
				{
					m_pPaddle2 = new CPaddle(myStage);
					if (m_pPaddle2 != null)
					{	
						trace("CGame: CreateObjectsOfGame -> paddle2 created successful");
						if (  m_pPaddle2.Init(l_pNode) )
							addChild(m_pPaddle2);
						else
							return false;
					}
					else
					{
						trace("2:CGame: CreateObjectsOfGame -> paddle2 was not created ");
						return false;
					}
				}
				
				//creates ball
				if (l_pNode.@objclass == "ball")
				{
					m_pBall = new CBall(myStage);
					if (m_pBall != null)
					{	
						trace("CGame: CreateObjectsOfGame -> ball created successful");
						if ( m_pBall.Init(l_pNode) )
							addChild(m_pBall);
						else
							return false;
					}
					else
					{
						trace("2:CGame: CreateObjectsOfGame -> ball was not created ");
						return false;
					}
				}
				
				//init values
				if (l_pNode.@objclass == "scores")
				{
					m_iGoalsA 	= l_pNode.@goalsA 	!= ""? l_pNode.@goalsA 	 : 0;
					m_iGoalsB 	= l_pNode.@goalsB 	!= ""? l_pNode.@goalsB 	 : 0;
					m_iMaxGoals = l_pNode.@maxGoals != ""? l_pNode.@maxGoals : 10;
				}
			}
			
			//draw a shape
			CreatingLineMidfield();

			//create scores
			CreatingScores();
			
			return true;
		}
				

		/**
		 * RemoveObjectsOfGame: remove objects when reload xml file
		 */
		public function RemoveObjectsOfGame():void
		{
			m_pPaddle1.Done();
			removeChild(m_pPaddle1);
			m_pPaddle2.Done();
			removeChild(m_pPaddle2);
			m_pBall.Done();
			removeChild(m_pBall);
			removeChild(m_pLine);
			trace("delete midfield line");
			removeChild(m_pGoalsA);
			trace("delete score P1");
			removeChild(m_pGoalsB);
			trace("delete score P2");
		}

		
		/**
		 * CreatingScores: Procedure to show points at screen 
		 */
		public function CreatingScores():void 
		{
			var l_pTextFormat:TextFormat = new TextFormat("OCR", 200);

			//creating goals P1
			m_pGoalsA = new TextField();
			m_pGoalsA.embedFonts = true;
			m_pGoalsA.width = 400;
			m_pGoalsA.height = 400;
			m_pGoalsA.defaultTextFormat = l_pTextFormat;
			m_pGoalsA.x = 130;
			m_pGoalsA.y = 50;
			m_pGoalsA.textColor = 0xFFFFFF;
			m_pGoalsA.text = m_iGoalsA.toString();
			addChild(m_pGoalsA);

			//creating goals P2
			m_pGoalsB = new TextField();
			m_pGoalsB.embedFonts = true;
			m_pGoalsB.width = 400;
			m_pGoalsB.height = 400;
			m_pGoalsB.defaultTextFormat = l_pTextFormat;
			m_pGoalsB.x = myStage.stageWidth - 200;
			m_pGoalsB.y = 50;
			m_pGoalsB.textColor = 0xFFFFFF;
			m_pGoalsB.text = m_iGoalsB.toString();
			addChild(m_pGoalsB);
		}

		
		/**
		 * CreatingLineMidfield: Procedure to draw the midfield line
		 */
		public function CreatingLineMidfield():void 
		{
			m_pLine = new Shape();
			if (m_pLine != null)
			{
				var i:			uint 	= 0;

				m_pLine.graphics.lineStyle(1.0, 0xFFFFFF, 1.0, true);
				
				m_pLine.x = myStage.stageWidth / 2;
				m_pLine.y = 0;

				var dy:			uint 	= m_pLine.y;
				//do dotted line
				for (i = 1; i < 30; i++)
				{
					dy += 10;
					m_pLine.graphics.lineTo(0, dy );
					dy += 15;
					m_pLine.graphics.moveTo(0, dy );
				}
				addChild(m_pLine);
				trace("CGame: Creating LineMidfield-> created...");
			}
		}

		
		/**
		 * StartGame: starts the game or a point, it depends of state of game
		 * @eventType : TimerEvent (timerBeginMatch)
		 */
		public function StartGame(e:TimerEvent):void
		{
			if (m_pBall != null)
			{
				switch(m_iStateGame)
				{
					//beginning: the movement will be random
					case 0:
						trace("2:starting game!");
						var d:int = m_pBall.GetRandomDirection();
						m_pBall.DecideDirection(d);
					break;
					//point to player 1
					case 1:
						trace("2:starting point to right!");
						m_pBall.visible = true;
						m_pBall.DecideDirection(m_pBall.LauchToRight());
		
					break;
					//point to player 2
					case 2:
						trace("2:starting point to left!");
						m_pBall.visible = true;
						m_pBall.DecideDirection(m_pBall.LauchToLeft());
					break;
					//somebody win
					case 3:
						trace("2:ending game!");
					break;
					
				}
			}
		}
		
	}

}